package cn.edu.hitsz.compiler.parser;

import cn.edu.hitsz.compiler.NotImplementedException;
import cn.edu.hitsz.compiler.ir.IRImmediate;
import cn.edu.hitsz.compiler.ir.IRValue;
import cn.edu.hitsz.compiler.ir.IRVariable;
import cn.edu.hitsz.compiler.ir.Instruction;
import cn.edu.hitsz.compiler.lexer.Token;
import cn.edu.hitsz.compiler.lexer.TokenKind;
import cn.edu.hitsz.compiler.parser.table.Production;
import cn.edu.hitsz.compiler.parser.table.Status;
import cn.edu.hitsz.compiler.symtab.SymbolTable;
import cn.edu.hitsz.compiler.utils.FileUtils;

import java.util.Deque;
import java.util.LinkedList;
import java.util.List;
import java.util.Stack;

// TODO: 实验三: 实现 IR 生成
public class IRGenerator implements ActionObserver {
    SymbolTable symbolTable;
    Stack<IRValue> stack = new Stack<>();
    private List<Instruction> instructions;

    public IRGenerator() {
        this.instructions = new LinkedList<>();
    }

    @Override
    public void whenShift(Status currentStatus, Token currentToken) {

        // 获取当前 token 的类型
        int tokenCode = currentToken.getKind().getCode();
        // TODO
        switch (tokenCode) {
            case 51: // id
                IRVariable variable = IRVariable.named(currentToken.getText());
                stack.push(variable);
                break;

            case 52: // IntConst
                int value = Integer.parseInt(currentToken.getText());
                IRImmediate immediate = IRImmediate.of(value);
                stack.push(immediate);
                break;
            default:

        }
    }

    @Override
    public void whenReduce(Status currentStatus, Production production) {
        // TODO
        switch (production.index()) {
            case 6: // S -> id = E
                IRValue expr = stack.pop(); // 弹出 E 的计算结果
                IRVariable var = (IRVariable) stack.pop(); // 栈顶为 id
                instructions.add(Instruction.createMov(var, expr));
                break;

            case 7: // S -> return E
                IRValue returnExpr = stack.pop(); // 弹出 E 的值
                instructions.add(Instruction.createRet(returnExpr));
                break;

            case 8: // E -> E + A
                IRValue aAdd = stack.pop(); // 弹出 A
                IRValue eAdd = stack.pop(); // 弹出 E
                IRVariable tempAdd = IRVariable.temp();
                instructions.add(Instruction.createAdd(tempAdd, eAdd, aAdd));
                stack.push(tempAdd);
                break;

            case 9: // E -> E - A
                IRValue aSub = stack.pop(); // 弹出 A
                IRValue eSub = stack.pop(); // 弹出 E
                IRVariable tempSub = IRVariable.temp();
                instructions.add(Instruction.createSub(tempSub, eSub, aSub));
                stack.push(tempSub);
                break;

            case 11: // A -> A * B
                IRValue bMul = stack.pop(); // 弹出 B
                IRValue aMul = stack.pop(); // 弹出 A
                IRVariable tempMul = IRVariable.temp();
                instructions.add(Instruction.createMul(tempMul, aMul, bMul));
                stack.push(tempMul);
                break;

        }
    }


    @Override
    public void whenAccept(Status currentStatus) {
        System.out.println("Program accepted.");
    }

    @Override
    public void setSymbolTable(SymbolTable table) {
        this.symbolTable = table;
    }

    public List<Instruction> getIR() {
        return instructions;
    }

    public void dumpIR(String path) {
        FileUtils.writeLines(path, getIR().stream().map(Instruction::toString).toList());
    }
}

